/*
 *  Game.cpp
 *  SpaceTrader
 *
 *  This class offers many of the essential methods for interacting with the GUI/View component.
 *
 */
#include <iostream>
#include "GuiTools.h"
#include "GuiButton.h"
#include "GuiTextBox.h"
#include "DBConnection.h"

/*
 *	This method loads an image into an optimized SDL_Surface and returns it. It also performs 
 *	colorkeying.
 * 
 */
SDL_Surface *load_image( std::string filename, bool colorKey)
{
	SDL_Surface *loadedImage = NULL;
	SDL_Surface *optimizedImage = NULL;
	
	//load the image
	loadedImage = IMG_Load(filename.c_str());
	
	//if the image loaded, create an optimized version
	if (loadedImage != NULL) {
		if(colorKey) 
			optimizedImage = SDL_DisplayFormat(loadedImage);
		else 
			optimizedImage = SDL_DisplayFormatAlpha(loadedImage);
		//Free old surface
		SDL_FreeSurface(loadedImage);
		
		//If the surface was optimized
		if (optimizedImage != NULL) {
			//Color key the surface
			if(colorKey) SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF));
		} else {
			std::cerr << "Error: Optimizing Image";
		}
		
	} else {
		std:: cerr << "Error: Loading Image";
	}
	return optimizedImage;
}


/*
 *	This method applies an input surface to surface to a destination surface(generally,
 *	the screen). Use this to render objects.
 *
 */
void apply_surface( int x, int y, SDL_Surface *source, SDL_Surface *destination)
{
	//no clipping
	SDL_Rect *clip = NULL;
	
	//set offset
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;
	
	SDL_BlitSurface( source, clip, destination, &offset );
}

/*
 *	This method applies an input surface to surface to a destination surface(generally,
 *	the screen). Use this to render objects.
 *
 */
void apply_surface_clip( int x, int y, SDL_Rect clip, SDL_Surface *source, SDL_Surface *destination)
{	
	//set offset
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;
	
	SDL_BlitSurface( source, &clip, destination, &offset );
}

/*
 *	Checks for collsions between two rectangular objects returns
 *	true in the event of a collision.
 *
 */
bool check_collision(SDL_Rect A, SDL_Rect B)
{
	//The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;
	
    //Calculate the sides of rect A
    leftA = A.x;
    rightA = A.x + A.w;
    topA = A.y;
    bottomA = A.y + A.h;
	
    //Calculate the sides of rect B
    leftB = B.x;
    rightB = B.x + B.w;
    topB = B.y;
    bottomB = B.y + B.h;
	
    //If any of the sides from A are outside of B
    if ( bottomA <= topB ) {
        return false;
    }
	
    if ( topA >= bottomB ) {
        return false;
    }
	
    if ( rightA <= leftB ) {
        return false;
    }
	
    if ( leftA >= rightB ) {
        return false;
    }
	
    //If none of the sides from A are outside B
    return true;
}

/*
 * Displays a formatted paragraph on the screen. lineLength is the approximate length of each line in the paragraph.
 * It should NEVER be greater than the length of the string.
 */
void showParagraph(int x, int y, std::string msg, int lineLength, TTF_Font *font, SDL_Surface *screen)
{
    std::vector<std::string> lines = parseStringIntoLines(msg, lineLength);
    
    for(unsigned int i = 0; i < lines.size(); i++){
        SDL_Color labelColor = {255,255,255};
		apply_surface(x, y+i*20, TTF_RenderText_Blended(font, lines[i].c_str(), labelColor), screen);
    }
}

/*
 * Takes in a long string and parses it into multiple lines. used in showParagraph() but
 * could be used somewhere else.
 */
std::vector<std::string> parseStringIntoLines(std::string msg, int charWidth)
{
    std::vector<std::string> res;
    unsigned int i = 0;
    std::string line = msg.substr(i,charWidth);
    while (line.length() >= (unsigned int)charWidth && ((unsigned int)i) <= msg.length()){
        char c = line.at(line.length()-1);
        if (i+line.length() == msg.length()){
            res.push_back(line);
            i = msg.length();
        } else if (c == '.' || c == '!' || c == '-' || c == '?' || c == ' ' || c ==','){
            res.push_back(line);
            i += charWidth;
        } else {
            int diff = 0;
            char e = 'a';
            while (e != ' '){
                diff++;
                e = line.at(line.length()-diff);
            }
            std::string newLine = line.substr(0, line.length()-diff);
            res.push_back(newLine);
            i += line.length()-diff+1;
        }
        line = msg.substr(i, charWidth + i < msg.length() ? charWidth + i : msg.length()-1);
    }
    return res;
}

void showPopUpWithMessage(std::string msg, SDL_Surface *screen)
{
    const int boxW = 300, boxH = 105;
	Uint32 boxColor = SDL_MapRGBA(screen->format, 0x00, 0x55, 0xAA, 0x10);
    SDL_Color white = {255, 255, 255};
	SDL_Rect infoBox;
	infoBox.x = 160;
	infoBox.y = 250;
	infoBox.w = boxW;
	infoBox.h = boxH;
    GuiButton okButton(230, 300, "", "OK");
    TTF_Font *font = TTF_OpenFont("Futura.ttc", 20);
    SDL_Surface *msgLabel = TTF_RenderText_Blended(font, msg.c_str(), white);
    
    SDL_Event event;
    bool isCleared = false;
    
    while (!isCleared){
        while (SDL_PollEvent(&event)){
            if (okButton.handle_input(event) == CLICKED){
                isCleared = true;
            }
        }
        SDL_FillRect(screen, &infoBox, boxColor);
        apply_surface(160, 270, msgLabel, screen);
        okButton.show(screen);
        
        //Update the screen
		if ( SDL_Flip( screen ) == -1 ) {
			std::cerr << "Error Updating screen." << std::endl;
		}
    }
    TTF_CloseFont(font);
    
}

std::string showLoginDialog(SDL_Surface *screen)
{
    const int boxW = 300, boxH = 150;
	Uint32 boxColor = SDL_MapRGBA(screen->format, 0x33, 0x66, 0x99, 0x00);
    SDL_Color white = {255, 255, 255};
	SDL_Rect infoBox;
	infoBox.x = screen->w/2 - boxW/2;
	infoBox.y = screen->h/2 - boxH/2;
	infoBox.w = boxW;
	infoBox.h = boxH;
    GuiButton loginButton(infoBox.x + infoBox.w/2 - 74, infoBox.y+infoBox.h - 60, "", "Login");
    GuiTextBox userNameField(infoBox.x + 95, infoBox.y + 2);
    GuiTextBox passwordField(infoBox.x + 95, infoBox.y + 32);
    TTF_Font *font = TTF_OpenFont("Futura.ttc", 20);
    SDL_Surface *unLabel = TTF_RenderText_Blended(font, "Username", white);
    SDL_Surface *pwLabel = TTF_RenderText_Blended(font, "Password", white);
    SDL_Event event;
    bool isDismissed = false;
    
    while (!isDismissed){
        while (SDL_PollEvent(&event)){
            if (loginButton.handle_input(event) == CLICKED){
				if(DBLogin(userNameField.getText(),passwordField.getText())) {
					std::cout << "Login Successful" << std::endl;
					return userNameField.getText();
				} else {
					std::cout << "Login Failed" << std::endl;
					isDismissed = true;
					return "";
				}
            }
            if (userNameField.handle_input(event, font, white) == CLICK) {
                passwordField.unFocus();
                userNameField.focus();
            }
            if (passwordField.handle_input(event, font, white) == CLICK) {
                userNameField.unFocus();
                passwordField.focus();
            }
            if (event.type == SDL_KEYUP){
                if (event.key.keysym.sym == SDLK_TAB){
                    if (!((userNameField.hasFocus() && passwordField.hasFocus()) || (!userNameField.hasFocus() && !passwordField.hasFocus()))){
                        userNameField.toggleFocus();
                        passwordField.toggleFocus();
                    }
                }
            }
        }
        SDL_FillRect(screen, &infoBox, boxColor);
        apply_surface(infoBox.x, infoBox.y, unLabel, screen);
        apply_surface(infoBox.x, infoBox.y + 30, pwLabel, screen);
        userNameField.show(screen);
        passwordField.show(screen);
        loginButton.show(screen);
        
        //Update the screen
		if ( SDL_Flip( screen ) == -1 ) {
			std::cerr << "Error Updating screen." << std::endl;
		}
    }
    TTF_CloseFont(font);
    
}


/*
 * Calculates standard font with appropriate size for text to be placed on a button.
 * Causes a memory leak right now so DO NOT use it.
 */
TTF_Font* getFont(std::string s)
{
    return TTF_OpenFont("Futura.ttc", 20-(strlen(s.c_str())-13));
}


/*
 * Final method called in the program to clean up.
 */
void clean_up()
{
	//TODO place all final "frees" for dynamically allocated game data
}